#pragma once
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
#include <unistd.h>

typedef struct
{
    uint32_t left;
    uint32_t top;
    uint32_t width;
    uint32_t height;
} ImageBlock;

#pragma GCC push_options
#pragma GCC optimize("O2,unroll-loops")

/***********************
 *
 *
 */
void memcopy(uchar *dst, uchar *src, uint32_t len)
{
    uint32_t *p_src = reinterpret_cast<uint32_t *>(src);
    uint32_t *p_dst = reinterpret_cast<uint32_t *>(dst);
    for (uint32_t i = 0; i < len / sizeof(uint32_t); i++)
    {
        p_dst[i] = p_src[i]; // 测试发现这种方法略快点
        // *p_dst++ = *p_src++;
    }
}

/*************************
 * src: buffer
 * dst: buffer2
 * bgra格式
 *
 */
void blockCopy(
    uchar *buffer, uchar *buffer2,
    uint32_t width, uint32_t height,
    uint32_t block_w, uint32_t block_h,
    uint32_t start_w, uint32_t start_h)
{
    uint32_t y, x;
    uint32_t *p = reinterpret_cast<uint32_t *>(buffer);
    uint32_t *p2 = reinterpret_cast<uint32_t *>(buffer2);
    for (y = start_h; y < start_h + block_h; y++)
    {
        for (x = start_w; x < start_w + block_w; x++)
        {
            p2[y * width + x] = p[y * width + x];
        }
    }
}

/*************************
 * src: buffer
 * src2: buffer2
 * bgra格式
 * return: 1-diff 0-same
 */
int blockCompare(
    uchar *buffer, uchar *buffer2,
    uint32_t width, uint32_t height,
    uint32_t block_w, uint32_t block_h,
    uint32_t start_w, uint32_t start_h)
{
    uint32_t y, x;
    uint32_t *p;
    uint32_t *p_copy;

    p = reinterpret_cast<uint32_t *>(buffer);
    p_copy = reinterpret_cast<uint32_t *>(buffer2);

    // uchar *p = (uchar *)(buffer);
    // uchar *p_copy = (uchar *)(buffer2);
    for (y = start_h; y < start_h + block_h; y++)
    {
        for (x = start_w; x < start_w + block_w; x++)
        {
            if (p_copy[y * width + x] != p[y * width + x])
                return 1;
        }
    }
    return 0;
}

/****************************
 * bgra image 分块
 * width, height 必须是 block_w, block_h的整数倍
 *
 */
void imageBlockingCompareAndCopy(
    uchar *buffer, uchar *buffer_copy,
    uint32_t width, uint32_t height,
    uint32_t block_w, uint32_t block_h,
    std::vector<ImageBlock> &image_blocks)
{
    uint32_t y, x;
    int ret;
    // std::vector<ImageBlock> image_blocks;
    image_blocks.clear();
    for (y = 0; y < height; y += block_h)
    {
        for (x = 0; x < width; x += block_w)
        {
            ret = blockCompare(buffer, buffer_copy, width, height, block_w, block_h, x, y);
            if (ret)
            {
                blockCopy(buffer, buffer_copy, width, height, block_w, block_h, x, y);
                image_blocks.push_back(ImageBlock{x, y, block_w, block_h});
            }
        }
    }
}

void cvt_color(uchar *buffer_bgra, uchar *buffer_bgr, int width, int height)
{
    cv::Mat image_bgra(height, width, CV_8UC4, (char *)buffer_bgra);
    cv::Mat image_bgr(height, width, CV_8UC3, (char *)buffer_bgr);
    cv::cvtColor(image_bgra, image_bgr, cv::COLOR_BGRA2BGR);
}

void resize(uchar *buffer_origin, uchar *buffer_resize, int old_width, int old_height, int new_width, int new_height)
{
    cv::Mat image_old(old_height, old_width, CV_8UC4, (char *)buffer_origin);
    cv::Mat image_new(new_height, new_width, CV_8UC4, (char *)buffer_resize);
    cv::resize(image_old, image_new, cv::Size(new_width, new_height));
}

#pragma GCC pop_options
